/*
 * 描          述:  <描述>
 * 修  改   人:  PengQingyang
 * 修改时间:  2022年4月15日
 * <修改描述:>
 */
package com.tx.component.social.context;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpSession;

import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.tx.component.social.SocialLoginPlugin;
import com.tx.component.social.SocialLoginPluginConfig;
import com.tx.component.social.model.SocialAccountType;
import com.tx.core.exceptions.util.AssertUtils;
import com.tx.core.util.ClassScanUtils;

/**
 * 第三方登陆账户容器<br/>
 * <功能详细描述>
 * 
 * @author  PengQingyang
 * @version  [版本号, 2022年4月15日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class SocialLoginContext
        implements ApplicationContextAware, InitializingBean, BeanNameAware {
    
    //    /** "forward"属性名称 */
    //    private static final String SOCIAL_ACCESS_TOKEN_ATTRIBUTE_NAME = SocialLoginContext.class
    //            .getName() + ".SOCIAL_ACCESS_TOKEN";
    
    /** "状态"属性名称 */
    private static final String STATE_ATTRIBUTE_NAME = SocialLoginContext.class
            .getName() + ".STATE";
    
    /** "forward"属性名称 */
    private static final String REDIRECT_URL_WHEN_CALLBACK_ATTRIBUTE_NAME = SocialLoginContext.class
            .getName() + ".REDIRECT_URL_WHEN_CALLBACK";
    
    /** "forward"属性名称 */
    private static final String SOCIAL_UNIQUEID_ATTRIBUTE_NAME = SocialLoginContext.class
            .getName() + ".SOCIAL_UNIQUEID";
    
    /** "forward"属性名称 */
    private static final String SOCIAL_ACCOUNT_TYPE_CODE_ATTRIBUTE_NAME = SocialLoginContext.class
            .getName() + ".SOCIAL_ACCOUNT_TYPE_CODE";
    
    /** 第三方登陆账户容器 */
    protected static SocialLoginContext context;
    
    /** applicationContext */
    protected static ApplicationContext applicationContext;
    
    /** beanName实例 */
    protected static String beanName;
    
    /** 账户类型MAP */
    private final Map<String, SocialAccountType> socialAccountTypeMap = new HashMap<>();
    
    /** 登陆插件MAP */
    private final Map<String, SocialLoginPlugin<?>> loginPluginMap = new HashedMap<>();
    
    /**
     * @param name
     */
    @Override
    public void setBeanName(String name) {
        SocialLoginContext.beanName = name;
    }
    
    /**
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        SocialLoginContext.applicationContext = applicationContext;
    }
    
    /**
     * 获取第三方登陆账户容器<br/>
     * <功能详细描述>
     * @return [参数说明]
     * 
     * @return SocialLoginAccountContext [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static SocialLoginContext getContext() {
        if (SocialLoginContext.context != null) {
            return SocialLoginContext.context;
        }
        synchronized (SocialLoginContext.class) {
            SocialLoginContext.context = applicationContext.getBean(beanName,
                    SocialLoginContext.class);
        }
        AssertUtils.notNull(SocialLoginContext.context, "context is null.");
        return SocialLoginContext.context;
    }
    
    /**
     * @throws Exception
     */
    @Override
    @SuppressWarnings("rawtypes")
    public void afterPropertiesSet() throws Exception {
        Set<Class<? extends SocialAccountType>> satClazzSet = ClassScanUtils
                .scanByParentClass(SocialAccountType.class, "com.tx");
        
        /** 第三方账户类型 */
        for (Class<? extends SocialAccountType> satClazzTemp : satClazzSet) {
            if (!satClazzTemp.isEnum()) {
                continue;
            }
            SocialAccountType[] sats = satClazzTemp.getEnumConstants();
            for (SocialAccountType satTemp : sats) {
                AssertUtils.notEmpty(satTemp.getCode(),
                        "socialAccountType.code is empty.");
                AssertUtils.notEmpty(satTemp.getName(),
                        "socialAccountType.name is empty.");
                
                this.socialAccountTypeMap.put(satTemp.getCode().toUpperCase(),
                        satTemp);
            }
        }
        
        for (SocialLoginPlugin slp : SocialLoginContext.applicationContext
                .getBeansOfType(SocialLoginPlugin.class)
                .values()) {
            this.loginPluginMap.put(
                    slp.getSocialAccountType().getCode().toUpperCase(),
                    slp);
        }
    }
    
    /** 构造函数级别为子类不可见 */
    protected SocialLoginContext() {
    }
    
    /**
     * 获取第三方账户类型集合<br/>
     * <功能详细描述>
     * @return [参数说明]
     * 
     * @return List<SocialAccountType> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<SocialAccountType> getSocialAccountTypes() {
        List<SocialAccountType> resList = new ArrayList<>(
                this.socialAccountTypeMap.values());
        
        return resList;
    }
    
    /**
     * 获取登陆插件<br/>
     * <功能详细描述>
     * @param plugin
     * @return [参数说明]
     * 
     * @return LoginPlugin<LoginPluginConfig> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public SocialAccountType getSocialAccountType(String code) {
        AssertUtils.notEmpty(code, "socialAccountTypeCode is empty.");
        
        SocialAccountType type = this.socialAccountTypeMap
                .get(code.toUpperCase());
        return type;
    }
    
    /**
     * 获取登陆插件<br/>
     * <功能详细描述>
     * @param plugin
     * @return [参数说明]
     * 
     * @return LoginPlugin<LoginPluginConfig> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public SocialLoginPlugin<? extends SocialLoginPluginConfig> getLoginPlugin(
            String code) {
        AssertUtils.notEmpty(code, "socialAccountTypeCode is empty.");
        
        SocialLoginPlugin<? extends SocialLoginPluginConfig> p = this.loginPluginMap
                .get(code.toUpperCase());
        return p;
    }
    
    /**
     * 将State值设置入session中<br/>
     * <功能详细描述>
     * @param session [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public void saveState(HttpSession session, String state) {
        AssertUtils.notNull(session, "session is null.");
        AssertUtils.notEmpty(state, "state is empty.");
        
        session.setAttribute(STATE_ATTRIBUTE_NAME, state);
    }
    
    /**
     * 从session从获取state值<br/>
     * <功能详细描述>
     * @param session
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public String getState(HttpSession session) {
        AssertUtils.notNull(session, "session is null.");
        
        String state = (String) session.getAttribute(STATE_ATTRIBUTE_NAME);
        
        return state;
    }
    
    /**
     * 将forwardUrl值设置入socialUniqueId中<br/>
     * <功能详细描述>
     * @param session [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public void saveSocialUniqueId(HttpSession session, String socialUniqueId) {
        AssertUtils.notNull(session, "session is null.");
        AssertUtils.notEmpty(socialUniqueId, "socialUniqueId is empty.");
        
        session.setAttribute(SOCIAL_UNIQUEID_ATTRIBUTE_NAME, socialUniqueId);
    }
    
    /**
     * 从session从获取socialUniqueId值<br/>
     * <功能详细描述>
     * @param session
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public String getSocialUniqueId(HttpSession session) {
        AssertUtils.notNull(session, "session is null.");
        
        String socialUniqueId = (String) session
                .getAttribute(SOCIAL_UNIQUEID_ATTRIBUTE_NAME);
        return socialUniqueId;
    }
    
    /**
     * 将socialAccountTypeCode值设置入socialAccountTypeCode中<br/>
     * <功能详细描述>
     * @param session [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public void saveSocialAccountTypeCode(HttpSession session,
            String socialAccountTypeCode) {
        AssertUtils.notNull(socialAccountTypeCode,
                "socialAccountTypeCode is null.");
        
        session.setAttribute(SOCIAL_ACCOUNT_TYPE_CODE_ATTRIBUTE_NAME,
                socialAccountTypeCode);
    }
    
    /**
     * 从session从获取socialAccountTypeCode值<br/>
     * <功能详细描述>
     * @param session
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public String getSocialAccountTypeCode(HttpSession session) {
        String socialAccountTypeCode = (String) session
                .getAttribute(SOCIAL_ACCOUNT_TYPE_CODE_ATTRIBUTE_NAME);
        return socialAccountTypeCode;
    }
    
    /**
     * 将forwardUrl值设置入session中<br/>
     * <功能详细描述>
     * @param session [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public void saveRedirectUrlWhenCallback(HttpSession session,
            String redirectUrlWhenCallback) {
        AssertUtils.notNull(session, "session is null.");
        AssertUtils.notEmpty(redirectUrlWhenCallback,
                "redirectUrlWhenCallback is empty.");
        
        session.setAttribute(REDIRECT_URL_WHEN_CALLBACK_ATTRIBUTE_NAME,
                redirectUrlWhenCallback);
    }
    
    /**
     * 从session从获取forwardUrl值<br/>
     * <功能详细描述>
     * @param session
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public String getRedirectUrlWhenCallback(HttpSession session) {
        AssertUtils.notNull(session, "session is null.");
        
        String redirectUrlWhenCallback = (String) session
                .getAttribute(REDIRECT_URL_WHEN_CALLBACK_ATTRIBUTE_NAME);
        return redirectUrlWhenCallback;
    }
}
